package cn.eaay.stock.service.impl;

import cn.eaay.stock.common.domain.StockExcelDomain;
import cn.eaay.stock.common.domain.StockInfoConfig;
import cn.eaay.stock.common.domain.StockUpDownLimitType;
import cn.eaay.stock.common.enums.ResponseCode;
import cn.eaay.stock.common.enums.StockDateFormat;
import cn.eaay.stock.mapper.StockMarketIndexInfoMapper;
import cn.eaay.stock.mapper.StockRtInfoMapper;
import cn.eaay.stock.service.StockService;
import cn.eaay.stock.utils.DateTimeUtil;
import cn.eaay.stock.vo.resp.PageResult;
import cn.eaay.stock.vo.resp.R;
import cn.eaay.stock.vo.stock.StockMarketIndexInfoVo;
import cn.eaay.stock.vo.stock.StockOuterMarketIndexVo;
import cn.eaay.stock.vo.stock.StockRtInfoVo;
import cn.eaay.stock.vo.stock.StockUpDownLimitVo;
import com.alibaba.excel.EasyExcel;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service("stockService")
public class StockServiceImpl implements StockService {

    @Resource
    private StockMarketIndexInfoMapper stockMarketIndexInfoMapper;

    @Resource
    private StockRtInfoMapper stockRtInfoMapper;

    @Resource
    private StockInfoConfig stockInfoConfig;

    /**
     * 获取国内大盘最新数据详情
     *
     * @return {@link R<List<StockMarketIndexInfoVo> 大盘指数详情列表> }
     */
    @Override
    public R<List<StockMarketIndexInfoVo>> getInnerSocketMarket() {
        // 获取最近股票有效交易日
        String lastAvData = DateTimeUtil.getLastDateString4Stock(DateTime.now());
        // 设置有效数据
        lastAvData = "20211228093900";
        // 获取国内大盘信息配置
        List<String> inner = stockInfoConfig.getInner();
        // 获取国内大盘最新详情
        List<StockMarketIndexInfoVo> infos = stockMarketIndexInfoMapper.getInnerStockMarket(inner, lastAvData);
        if (CollectionUtils.isEmpty(infos)) {
            return R.error(ResponseCode.ERROR.getMessage());
        }
        return R.ok(infos);
    }

    /**
     * 获取国外大盘指数
     *
     * @return
     */
    @Override
    public R<List<StockOuterMarketIndexVo>> getOuterStockMarket() {
        // 获取最近股票有效交易日
        String marketDay = DateTimeUtil.getLastDateString4Stock(DateTime.now());
        // 设置有效数据
        marketDay = "20220221145800";
        // 获取外盘配置信息
        List<String> outerMarketIdList = stockInfoConfig.getOther();
        List<StockOuterMarketIndexVo> outerMarketList = stockMarketIndexInfoMapper.getOuterStockMarket(outerMarketIdList, marketDay);
        if (CollectionUtils.isEmpty(outerMarketList)) {
            return R.error(ResponseCode.ERROR.getMessage());
        }
        return R.ok(outerMarketList);
    }

    /**
     * 沪深两市个股涨幅分时行情数据查询
     *
     * @return {@link R<List<StockRtInfoVo>>} 个股行情Vo列表
     */
    @Override
    public R<List<StockRtInfoVo>> getStockIncrease() {
        List<StockRtInfoVo> infos = stockRtInfoMapper.getStockIncrease();
        if (CollectionUtils.isEmpty(infos)) {
            return R.error(ResponseCode.ERROR.getMessage());
        }
        return R.ok(infos);
    }

    /**
     * 沪深两市个股行情列表查询 ,以时间顺序和涨幅排序分页查询
     *
     * @param page     当前页码
     * @param pageSize 每页数量
     * @return
     */
    @Override
    public R<PageResult> getStockAll(Integer page, Integer pageSize) {
        // TODO: 校验分页参数
        PageHelper.startPage(page, pageSize);
        List<StockRtInfoVo> infos = stockRtInfoMapper.getStockAll();
        if (CollectionUtils.isEmpty(infos)) {
            return R.error("暂无数据");
        }
        PageInfo<StockRtInfoVo> pageInfo = new PageInfo<>(infos);
        PageResult<StockRtInfoVo> pageResult = new PageResult<>(pageInfo);
        return R.ok(pageResult);
    }

    /**
     * 获取涨停跌停数
     * 沪深两市涨跌停分时行情数据查询，查询T日每分钟的涨跌停数据
     *
     * @return
     */
    @Override
    public R<StockUpDownLimitVo> getStockUpDownLimitCount() {
        // 查询涨停数量
        List<Map<String, Object>> upLimit = stockRtInfoMapper.getUpDownLimitCount(StockUpDownLimitType.UP_LIMIT_TYPE);
        String curDate = DateTime.now().toString(DateTimeFormat.forPattern(StockDateFormat.CP_MM.getSdf()));
        if (CollectionUtils.isEmpty(upLimit)) {
            HashMap map = new HashMap();
            map.put("time", curDate);
            map.put("count", 0);
            upLimit.add(map);
        }
        // 查询跌停数量
        List<Map<String, Object>> downLimit = stockRtInfoMapper.getUpDownLimitCount(StockUpDownLimitType.DOWN_LIMIT_TYPE);
        if (CollectionUtils.isEmpty(downLimit)) {
            HashMap map = new HashMap();
            map.put("time", curDate);
            map.put("count", 0);
            downLimit.add(map);
        }
        //组装数据
        StockUpDownLimitVo upDownLimit = StockUpDownLimitVo.builder()
                .upList(upLimit).downList(downLimit).build();
        return R.ok(upDownLimit);
    }

    /**
     * 涨幅榜数据分页导出到excel
     *
     * @param response
     * @param page
     * @param pageSize
     */
    @Override
    public void exportStockExcel(HttpServletResponse response, Integer page, Integer pageSize) {
        try {
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
            String fileName = URLEncoder.encode("stockRt", "UTF-8");
            response.setHeader("content-disposition", "attachment;filename=" + fileName + ".xlsx");
            PageHelper.startPage(page, pageSize);
            List<StockRtInfoVo> infos = stockRtInfoMapper.getStockAll();
            List<StockExcelDomain> excelDomains = new ArrayList<>();
            Gson gson = new Gson();
            infos.forEach(row -> {
                StockExcelDomain excelDomain = gson.fromJson(gson.toJsonTree(row), StockExcelDomain.class);
                excelDomains.add(excelDomain);
            });
            EasyExcel.write(response.getOutputStream(), StockExcelDomain.class)
                    .sheet("stockRt").doWrite(excelDomains);
        } catch (IOException e) {
            log.error("Excel导出错误 => {}", e);
            e.printStackTrace();
        }
    }

    /**
     * 获取股票成交量对比
     * 统计每分钟沪深两市的成交量
     *
     * @return
     */
    @Override
    public R<Map> getStockTradeVolumeCompare() {
        // 获取最近有效交易日时间
        DateTime target = DateTimeUtil.getLastDate4Stock(DateTime.now());
        // 转为string
        String curStr = DateTimeUtil.parseToString4Stock(target);
        curStr = "20220103145900";
        // 获取T交易日成交量数据
        List<Map> nowInfos = stockMarketIndexInfoMapper.getStockTradeVolume(curStr);
        if (CollectionUtils.isEmpty(nowInfos)) {
            nowInfos = Collections.emptyList();
        }
        // 获取T-1日的时间
        String preStr = DateTimeUtil.parseToString4Stock(DateTimeUtil.getPreviousTradingDay(target));
        preStr = "20211226145900";
        // 获取T-1交易日成交数据量
        List<Map> preInfos = stockMarketIndexInfoMapper.getStockTradeVolume(preStr);
        if (CollectionUtils.isEmpty(preInfos)) {
            preInfos = Collections.emptyList();
        }
        // 封装数据
        Map<String, List> map = new HashMap<>();
        map.put("volList", nowInfos);
        map.put("yesVolList", preInfos);
        return R.ok(map);
    }

    /**
     * 获取单个股票每日K线数据，根据时间区间查询
     *
     * @return
     */
    @Override
    public R<List<Map>> getDayKLinData(String stockCode) {
        // TODO: 校验参数 stockCode
        // 当前时间减去60天的时间
        DateTime subDateTime = DateTime.now().minusDays(60);
        // 获取日期字符串
        String dateTimeStr = subDateTime.toString(DateTimeFormat.forPattern("yyyyMMdd"));
        List<Map> infos = stockRtInfoMapper.getDayKLineData(stockCode, dateTimeStr);
        if (CollectionUtils.isEmpty(infos)) {
            return R.error("暂无数据");
        }
        return R.ok(infos);
    }

    /**
     * 获取个股分时K线行情，查询时间间隔是T日开盘到当前时间
     *
     * @param stockCode 股票代码
     * @return
     */
    @Override
    public R<List<Map>> getStockScreenMinuteSharing(String stockCode) {
        // TODO: 参数校验 stockCode
        // 获取最近有效交易日时间
        String tDate = DateTimeUtil.getLastDateString4Stock(DateTime.now());
        tDate = "20220107";
        // 查询
        List<Map> infos = stockRtInfoMapper.getStockScreenMinuteSharing(stockCode, tDate);
        if (CollectionUtils.isEmpty(infos)) {
            return R.error("暂无数据");
        }
        return R.ok(infos);
    }

    /**
     * 统计当前时间下股票涨跌在各个区间的数量
     * 若当前时间不是一个有效交易日，则以最近的一个股票交易日作为查询点
     *
     * @return
     */
    @Override
    public R<Map> getUpDownScope() {
        // 获取当前最近有效的股票交易时间，精确到分钟
        DateTime target = DateTimeUtil.getLastDate4Stock(DateTime.now());
        // 转为字符串
        String last = DateTimeUtil.getLastDateString4Stock(target);
        // 设置临时数据
        last = "20220106145800";
        // 查询数据
        List<Map> maps = stockRtInfoMapper.getStockUpDownScope(last);
        if (CollectionUtils.isEmpty(maps)) {
            return R.error("暂无数据");
        }
        // 获取顺序展示的title数据
        List<String> upDownRange = stockInfoConfig.getUpDownRange();
        // 将数据顺序展示给前端
        List<Map> newInfos = upDownRange.stream().map(key -> {
            Optional<Map> title = maps.stream().filter(map -> key.equals(map.get("title"))).findFirst();
            Map map = null;
            if (title.isPresent()) {
                map = title.get();
            } else {
                map = new HashMap();
                map.put("title", key);
                map.put("count", 0);
            }
            return map;
        }).collect(Collectors.toList());

        // 组装数据
        Map<String, Object> data = new HashMap<>();
        data.put("time", target.toString("yyyy-MM-dd HH:mm:ss"));
        data.put("infos", newInfos);
        return R.ok(data);
    }


}
